package com.kaibes.orm.core.core;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

import com.kaibes.orm.core.listener.CacheListener;
import com.kaibes.orm.core.plus.UpdateBuilderPlus;
import com.kaibes.orm.curd.DeleteBuilder;
import com.kaibes.orm.curd.InsertBuilder;
import com.kaibes.orm.curd.OrderType;
import com.kaibes.orm.curd.Query;
import com.kaibes.orm.curd.QueryBuilder;
import com.kaibes.orm.curd.SelectBuilder;

public interface TableService<E> {

    Mapper<E> getMapper();

    default boolean isLargeThanZero(Number id) {
        if (id != null) {
            if (id instanceof Long) {
                Long longId = (Long) id;
                return longId > 0;
            } else if (id instanceof Integer) {
                Integer integerId = (Integer) id;
                return integerId > 0;
            }
        }
        return false;
    }

    default String getIdName() {
        return getMapper().getTableColumn().getIdColumn().getName();
    }

    // ======================== save
    default <T> List<T> save(Object data) {
        if (data == null) {
            throw new RuntimeException("不能将空数据插入数据库中");
        } else if (data instanceof List) {
            List<?> list = (List<?>) data;
            if (list.isEmpty()) {
                throw new RuntimeException("不能将空数据插入数据库中");
            } else {
                return getMapper().insert(InsertBuilder.newBuilder().setDatas(list).build());
            }
        } else {
            return getMapper().insert(InsertBuilder.newBuilder().addData(data).build());
        }
    }

    // ======================== remove
    default int remove(Query... queries) {
        return getMapper().delete(DeleteBuilder.newBuilder().setQueries(Arrays.asList(queries)).build());
    }

    default int removeById(Object id) {
        return remove(QueryBuilder.newBuilder().eq(getIdName(), id).build());
    }

    default int removeByIdArr(Object... ids) {
        return remove(QueryBuilder.newBuilder().inArray(getIdName(), ids).build());
    }
    
    default int removeByIdList(List<?> ids) {
        return remove(QueryBuilder.newBuilder().inList(getIdName(), ids).build());
    }

    // ======================== update
    default int update(Object e, Query[] queries, String...inogres) {
        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e).delValue(inogres).setQueries(Arrays.asList(queries)).build());
    }
    
    default int update(Object e, Query query, String...inogres) {
        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e).delValue(inogres).addQuery(query).build());
    }
    
//    default int updateById(Object e, List<? extends Number> ids) {
//        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getMapper()).addQuery(QueryBuilder.newBuilder().inList("id", ids).build()).build());
//    }
//    
//    default int updateByIds(Object e, String... inogres) {
//        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getIdName()).delValue(inogres).createQueryById(getIdName()).build());
//    }

    default int updateById(Object e, Object id) {
        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getIdName())
                .addQuery(QueryBuilder.newBuilder().eq(getIdName(), id).build()).build());
    }

    default int updateByIds(Object e, List<?> ids) {
        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getIdName())
                .addQuery(QueryBuilder.newBuilder().inList(getIdName(), ids).build()).build());
    }
    
//    default int update(E e) {
//        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getMapper()).createQueryById("id").build());
//    }
//
//    default int updateById(Object e) {
//        return getMapper().update(UpdateBuilderPlus.newBuilder().setData(e, getMapper()).createQueryById("id").build());
//    }

    // 为了防止歧义
    // ======================== select many
    default List<E> list() {
        return getMapper().select(SelectBuilder.newBuilder().build());
    }

    default List<E> list(List<Query> queries) {
        return getMapper().select(SelectBuilder.newBuilder().setQueries(queries).build());
    }

    default List<E> list(List<Query> queries, List<String> columns) {
        return getMapper().select(SelectBuilder.newBuilder().setQueries(queries).setColumns(columns).build());
    }

    default List<E> list(List<Query> queries, String... columns) {
        return list(queries, Arrays.asList(columns));
    }

    default List<E> list(List<String> columns, Query... queries) {
        return list(Arrays.asList(queries), columns);
    }

    // 这个方法是为了防止下面的两个方法发生歧义
    // 如果没有这方法，当调用list(query)，系统将不知道是要调用list(Query... queries)，还是list(Query query,
    // String... columns)
    default List<E> list(Query query) {
        return getMapper().select(SelectBuilder.newBuilder().addQuery(query).build());
    }

    default List<E> list(Query... queries) {
        return list(Arrays.asList(queries));
    }

    default List<E> list(Query query, String... columns) {
        return list(Arrays.asList(columns), query);
    }

    default List<E> list(String... columns) {
        return list(Arrays.asList(columns));
    }

    default List<E> listByIds(List<?> ids) {
        return list(QueryBuilder.newBuilder().inList(getIdName(), ids).build());
    }

    default List<E> listByNotIds(List<?> ids) {
        return list(QueryBuilder.newBuilder().notInList(getIdName(), ids).build());
    }
    
    default List<E> listId(List<Query> queries) {
        return list(queries, getIdName());
    }
    
    // ======================== select one
    default E get(List<Query> queries, List<String> columns) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().setQueries(queries).setColumns(columns).build());
    }

    default E get(List<Query> queries, String... columns) {
        return get(queries, Arrays.asList(columns));
    }

    default E get(List<String> columns, Query... queries) {
        return get(Arrays.asList(queries), columns);
    }

    default E get(Query query) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().addQuery(query).build());
    }
    
    default E get(Query query, String column, OrderType type) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().addQuery(query).addOrder(column, type).build());
    }
    
    default E get(Query... queries) {
        return get(Arrays.asList(queries));
    }

    default E get(Query query, String... columns) {
        return get(Arrays.asList(columns), query);
    }

    default <T> T get(Query query, Class<T> clazz) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().addQuery(query).build(), clazz);
    }

    default E getById(Object id, List<String> columns) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().setColumns(columns)
                .addQuery(QueryBuilder.newBuilder().eq(getIdName(), id).build()).build());
    }

    default E getById(Object id, String... columns) {
        return getById(id, Arrays.asList(columns));
    }
    
    default E getLast(String... columns) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().setColumns(Arrays.asList(columns)).addOrder(getIdName(), OrderType.DESC).setSize(1).build());
    }
    default E getFirst(String... columns) {
        return getMapper().selectFirst(SelectBuilder.newBuilder().setColumns(Arrays.asList(columns)).addOrder(getIdName(), OrderType.ASC).setSize(1).build());
    }

    // ===============
    default long count() {
        return getMapper().count();
    }

    default long count(Query... queries) {
        return getMapper().count(SelectBuilder.newBuilder().setQueries(Arrays.asList(queries)).build());
    }

    default boolean isEmpty() {
        return getMapper().count() == 0;
    }

    // =============
    default Page<E> page(int pageIndex, int pageSize, Query... queries) {
        return getMapper().page(SelectBuilder.newBuilder().addQuery(queries).build(), pageIndex, pageSize);
    }

    default Page<E> page(int pageIndex, int pageSize, List<Query> queries) {
        return getMapper().page(SelectBuilder.newBuilder().addQuery(queries).build(), pageIndex, pageSize);
    }

    default Page<E> page(int pageIndex, int pageSize) {
        return getMapper().page(SelectBuilder.newBuilder().build(), pageIndex, pageSize);
    }
    
    default Page<E> pageAsc(int pageIndex, int pageSize, String columnName, Query... queries) {
        return getMapper().page(SelectBuilder.newBuilder().addQuery(queries).addOrder(columnName, OrderType.ASC).build(), pageIndex, pageSize);
    }
    default Page<E> pageDesc(int pageIndex, int pageSize, String columnName, Query... queries) {
        return getMapper().page(SelectBuilder.newBuilder().addQuery(queries).addOrder(columnName, OrderType.DESC).build(), pageIndex, pageSize);
    }

    default Page<E> pageAsc(int pageIndex, int pageSize, String columnName) {
        return getMapper().page(SelectBuilder.newBuilder().addOrder(columnName, OrderType.ASC).build(), pageIndex,
                pageSize);
    }

    default Page<E> pageDesc(int pageIndex, int pageSize, String columnName) {
        return getMapper().page(SelectBuilder.newBuilder().addOrder(columnName, OrderType.DESC).build(), pageIndex,
                pageSize);
    }
    
    // =================
    @SuppressWarnings("unchecked")
    default void initMapper() {
        Type superClass = getClass().getGenericSuperclass();
        Class<E> entityClass = (Class<E>) ((ParameterizedType) superClass).getActualTypeArguments()[0];
        getMapper().setEntityClass(entityClass);
    }
    
    default void clearCache() throws SQLException {
        CacheListener<E> listener = getMapper().getCacheListener();
        if (listener != null) {
            listener.clear();
        }
    }

    //==================
    default QueryBuilder query() {
        return QueryBuilder.newBuilder();
    }
}
